package com.yk.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yk.api.system.dto.*;
import com.yk.common.core.constant.NumberConstant;
import com.yk.common.core.domain.BasePageQuery;
import com.yk.common.core.domain.LoginUser;
import com.yk.common.core.domain.PageResult;
import com.yk.common.core.domain.Result;
import com.yk.common.core.enums.RoleTypeEnum;
import com.yk.common.core.utils.LoginHelper;
import com.yk.common.redis.service.RedisService;
import com.yk.system.convert.DeviceRoleConvert;
import com.yk.system.entity.Device;
import com.yk.system.entity.DeviceRole;
import com.yk.system.entity.Message;
import com.yk.system.entity.User;
import com.yk.system.service.DeviceRoleService;
import com.yk.system.service.DeviceService;
import com.yk.system.service.MessageService;
import com.yk.system.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * 设备权限控制器 yk-system
 *
 * @author lmx
 * @since 2023-11-08
 */
@Api(tags = "设备权限控制器")
@RestController
@RequestMapping("/deviceRole")
@RequiredArgsConstructor
public class DeviceRoleController {

    private final DeviceRoleService deviceRoleService;
    private final DeviceService deviceService;
    private final DeviceRoleConvert deviceRoleConvert;
    private final RedisService redisService;
    private final MessageService messageService;
    private final UserService userService;

    @GetMapping("/userDeviceRole")
    @ApiOperation("获取当前用户的设备权限")
    public Result<List<UserDeviceRoleDTO>> userDeviceRole() {
        Long userId = LoginHelper.getLoginUserId();
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        lambda.select(DeviceRole::getDeviceId, DeviceRole::getRoleType, DeviceRole::getExpiredTime);
        lambda.eq(DeviceRole::getUserId, userId);
        lambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
        List<DeviceRole> list = Optional.ofNullable(deviceRoleService.list(lambda)).orElse(CollUtil.newArrayList());
        List<UserDeviceRoleDTO> returnList = list.stream().map(item -> {
            UserDeviceRoleDTO dto = new UserDeviceRoleDTO();
            dto.setDeviceId(item.getDeviceId());
            dto.setRoleType(item.getRoleType());
            Date date = DateUtil.parseDateTime("9999-12-31 00:00:00");
            if (Objects.nonNull(item.getExpiredTime()) && date.compareTo(item.getExpiredTime()) != 0) {
                dto.setExpiredTime(item.getExpiredTime());
            }
            return dto;
        }).collect(Collectors.toList());
        return Result.data(returnList);
    }

    @GetMapping("/adminDeviceRole")
    @ApiOperation("获取当前用户可管理设备")
    public Result<List<DeviceDTO>> adminDeviceRole() {
        Long userId = LoginHelper.getLoginUserId();
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        lambda.select(DeviceRole::getDeviceId, DeviceRole::getRoleType, DeviceRole::getExpiredTime);
        lambda.eq(DeviceRole::getUserId, userId);
        lambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
        lambda.in(DeviceRole::getRoleType, CollUtil.newArrayList(RoleTypeEnum.ADMIN.getCode(), RoleTypeEnum.MANAGE.getCode()));
        lambda.eq(DeviceRole::getDelFlag, NumberConstant.ZERO_STR);
        List<DeviceRole> list = Optional.ofNullable(deviceRoleService.list(lambda)).orElse(CollUtil.newArrayList());
        List<DeviceDTO> returnList = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(list)){
            list.forEach(it -> {
                Device device = deviceService.getById(it.getDeviceId());
                if (Objects.isNull(device)){
                    return;
                }
                DeviceDTO dto = new DeviceDTO();
                dto.setId(device.getId());
                dto.setDeviceName(device.getDeviceName());
                returnList.add(dto);
            });
        }
        return Result.data(returnList);
    }

    @GetMapping("/unReception/{deviceId}")
    @ApiOperation("断开接收")
    public Result<Boolean> unReception(@PathVariable Long deviceId) {
        Long userId = LoginHelper.getLoginUserId();
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        lambda.eq(DeviceRole::getUserId, userId);
        lambda.eq(DeviceRole::getDeviceId, deviceId);
        lambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
        DeviceRole deviceRole = deviceRoleService.getOne(lambda);
        Assert.notNull(deviceRole, "设备权限不存在");
        if (RoleTypeEnum.ADMIN.getCode().equals(deviceRole.getRoleType())) {
            return Result.fail("管理员不能断开接收");
        }
        deviceRole.setStatus(NumberConstant.ONE_STR);
        deviceRoleService.updateById(deviceRole);
        // 发送系统通知
        LoginUser loginUser = LoginHelper.getLoginUser();
        Device device = deviceService.getById(deviceRole.getDeviceId());
        String message = loginUser.getNickname() + "断开分享设备：" + device.getDeviceName();
        messageService.systemMessage("设备断开分享通知", deviceRole.getAdminId(), message, NumberConstant.ZERO_STR);
        return Result.ok();
    }

    @PostMapping("/phone")
    @ApiOperation("管理者共享手机号")
    public Result<Boolean> message2Phone(@RequestBody @Validated DeviceRoleDTO dto) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Assert.notNull(dto.getPhone(), "手机号不能为空");
        Assert.notNull(dto.getDeviceId(), "设备id不能为空");
        LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
        lambda.eq(User::getUserName, dto.getPhone()).or().eq(User::getPhone, dto.getPhone());
        User user = userService.getOne(lambda);
        Assert.notNull(user, "用户不存在");
        Device device = deviceService.getById(dto.getDeviceId());
        Assert.notNull(device, "设备不存在");
        messageService.checkShare(user.getId(), loginUser.getUserId(), NumberConstant.ONE_STR, device.getId());
        deviceRoleService.checkShare(dto.getDeviceId(), "对方已接收该设备", user.getId());
        dto.setUserId(user.getId());
        dto.setAdminId(loginUser.getUserId());
        DeviceRole deviceRole = deviceRoleConvert.dto2Entity(dto);
        long deviceRoleId = IdWorker.getId();
        deviceRole.setId(deviceRoleId);
        deviceRole.setDelFlag(NumberConstant.TWO_STR);
        deviceRoleService.save(deviceRole);
        String shareMessageUrl = "向" + user.getNickName() + "共享了设备" + device.getDeviceName();
        messageService.shareMessage(shareMessageUrl, loginUser.getUserId(), user.getId(), deviceRoleId, null, device.getId());
        String sharedMessageUrl = loginUser.getNickname() + "向您共享了设备" + device.getDeviceName();
        messageService.sharedMessage(sharedMessageUrl, loginUser.getUserId(), user.getId(), deviceRoleId, null, device.getId());
        return Result.ok();
    }

    @PostMapping("/batchPhone")
    @ApiOperation("管理者批量共享手机号")
    public Result<Boolean> batchMessage2Phone(@RequestBody @Validated DeviceRoleDTO dto) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Assert.notNull(dto.getPhone(), "手机号不能为空");
        Assert.notEmpty(dto.getDeviceIdList(), "设备id不能为空");
        LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
        lambda.eq(User::getUserName, dto.getPhone()).or().eq(User::getPhone, dto.getPhone());
        User user = userService.getOne(lambda);
        Assert.notNull(user, "用户不存在");
        List<Long> deviceIdList = dto.getDeviceIdList();
        List<DeviceRole> deviceRoleList = CollUtil.newArrayList();
        deviceIdList.forEach(it -> {
            Device device = deviceService.getById(it);
            Assert.notNull(device, "有设备不存在，请刷新页面重试");
            messageService.batchCheckShare(device, user.getId(), loginUser.getUserId(), NumberConstant.ONE_STR);
            deviceRoleService.checkShare(dto.getDeviceId(), "对方已接收该设备", user.getId());
            dto.setUserId(user.getId());
            dto.setAdminId(loginUser.getUserId());
            DeviceRole deviceRole = deviceRoleConvert.dto2Entity(dto);
            long deviceRoleId = IdWorker.getId();
            deviceRole.setId(deviceRoleId);
            deviceRole.setDelFlag(NumberConstant.TWO_STR);
            deviceRole.setDeviceId(it);
            deviceRoleList.add(deviceRole);
            String shareMessageUrl = "向" + user.getNickName() + "共享了设备" + device.getDeviceName();
            messageService.shareMessage(shareMessageUrl, loginUser.getUserId(), user.getId(), deviceRoleId, null, device.getId());
            String sharedMessageUrl = loginUser.getNickname() + "向您共享了设备" + device.getDeviceName();
            messageService.sharedMessage(sharedMessageUrl, loginUser.getUserId(), user.getId(), deviceRoleId, null, device.getId());
        });
        deviceRoleList.forEach(deviceRoleService::save);
        return Result.ok();
    }

    @PostMapping("/save/phone")
    @ApiOperation("接收者接收手机号")
    public Result<Boolean> save2Phone(@RequestBody @Validated MessageDTO dto) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Assert.notNull(dto.getReceiveStatus(), "接收状态不能为空");
        Assert.notNull(dto.getId(), "消息Id不能为空");
        Message message = messageService.getById(dto.getId());
        Assert.notNull(message, "消息不存在");
        Assert.notNull(message.getDeviceRoleId(), "接收失败");
        DeviceRole deviceRole = deviceRoleService.getByIdIgnoreDel(message.getDeviceRoleId());
        Assert.notNull(deviceRole, "分享已失效");
        if (NumberConstant.ZERO_STR.equals(deviceRole.getDelFlag())) {
            message.setReceiveStatus(dto.getReceiveStatus());
            messageService.updateById(message);
            return Result.fail("该设备已接收");
        }
        Device device = deviceService.getById(deviceRole.getDeviceId());
        String shareMessageUrl = null;
        if (dto.getReceiveStatus()) {
            deviceRole.setDelFlag(NumberConstant.ZERO_STR);
            deviceRoleService.updateDelDeviceRole(deviceRole);
            shareMessageUrl = loginUser.getNickname() + "接收了您分享的设备" + device.getDeviceName();
            messageService.shareMessage(shareMessageUrl, message.getShareId(), message.getSharedId(),
                    deviceRole.getId(), Boolean.TRUE, device.getId());
        } else {
            shareMessageUrl = loginUser.getNickname() + "拒绝接收您分享的设备" + device.getDeviceName();
            messageService.shareMessage(shareMessageUrl, message.getShareId(), message.getSharedId(),
                    deviceRole.getId(), Boolean.FALSE, device.getId());
        }
        message.setReceiveStatus(dto.getReceiveStatus());
        messageService.updateById(message);
        return Result.ok();
    }

    @ApiOperation("查询设备权限码")
    @GetMapping("/getRoleCode/{deviceId}")
    public Result<String> getRoleCode(@PathVariable Long deviceId) {
        DeviceRole deviceRole = deviceRoleService.getDeviceRole(deviceId);
        if (Objects.isNull(deviceRole)) {
            return Result.data(RoleTypeEnum.VIEW.getCode());
        }
        return Result.data(deviceRole.getRoleType());
    }

    @PostMapping("/update")
    @ApiOperation("修改")
    public Result<Boolean> updateById(@RequestBody @Validated DeviceRoleDTO dto) {
        deviceRoleService.updateDeviceRole(deviceRoleConvert.dto2Entity(dto));
        return Result.ok();
    }

    @GetMapping("/deleteById/{id}")
    @ApiOperation("删除")
    public Result<Boolean> deleteById(@PathVariable(value = "id") Long id) {
        return Result.data(deviceRoleService.removeById(id));
    }

    @PostMapping("/list")
    @ApiOperation("查询列表")
    public Result<List<DeviceRoleDTO>> list(@RequestBody DeviceRoleDTO param) {
        Assert.notNull(param.getDeviceId(), "设备ID不能为空");
        List<DeviceRoleDTO> list = CollUtil.newArrayList();
        LambdaQueryWrapper<DeviceRole> lambda = new QueryWrapper<DeviceRole>().lambda();
        buildCondition(lambda, param);
        deviceRoleService
                .list(lambda)
                .forEach(it -> list.add(deviceRoleConvert.entity2Dto(it)));
        list.forEach(deviceRoleService::assignDeviceRole);
        return Result.data(list);
    }

    @PostMapping("/page")
    @ApiOperation("分页查询")
    public PageResult<DeviceRoleDTO> page(@RequestBody BasePageQuery<DeviceRoleDTO> pageParam) {
        DeviceRoleDTO param = pageParam.getParam();
        Assert.notNull(param.getDeviceId(), "设备ID不能为空");
        DeviceRole deviceRole = deviceRoleService.getDeviceRole(param.getDeviceId());
        if (Objects.isNull(deviceRole)) {
            return PageResult.success(CollUtil.newArrayList(), 0);
        }
        if (!RoleTypeEnum.ADMIN.getCode().equals(deviceRole.getRoleType()) && !RoleTypeEnum.MANAGE.getCode().equals(deviceRole.getRoleType())) {
            return PageResult.success(CollUtil.newArrayList(), 0);
        }
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        buildCondition(lambda, param);
        IPage<DeviceRoleDTO> page = deviceRoleService.page(new Page<>(pageParam.getPageNum(), pageParam.getPageSize()), lambda)
                .convert(deviceRoleConvert::entity2Dto);
        page.getRecords().forEach(deviceRoleService::assignDeviceRole);
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    @PostMapping("/pageByTime")
    @ApiOperation("分页查询-根据更新时间分页")
    public PageResult<DeviceRoleDTO> pageByTime(@RequestBody BasePageQuery<DeviceRoleDTO> pageParam) {
        DeviceRoleDTO param = pageParam.getParam();
        Assert.notNull(param.getDeviceId(), "设备ID不能为空");
        List<DeviceRoleDTO> list = deviceRoleService.pageByTime(param.getDeviceId());
        if (CollUtil.isEmpty(list)) {
            return PageResult.success(CollUtil.newArrayList(), 0);
        }
        int size = list.size();
        int index = 0;
        if (Objects.isNull(param.getId())) {
            index = CollUtil.indexOf(list, matcher -> matcher.getId().equals(param.getId()));
        }
        if (index > -1) {
            int start = index == 0 ? 0 : index + 1;
            int toIndex = start + pageParam.getPageSize().intValue();
            if (list.size() < toIndex) {
                toIndex = list.size();
            }
            list = list.subList(start, toIndex);
        }
        list.forEach(deviceRoleService::assignDeviceRole);
        return PageResult.success(list, size);
    }

    @PostMapping("/page2Alarm")
    @ApiOperation("分页查询-报警接收配置")
    public PageResult<DeviceRoleAlarmDTO> page2Alarm(@RequestBody BasePageQuery<DeviceRoleAlarmDTO> pageParam) {
        IPage<DeviceRoleAlarmDTO> page = deviceRoleService.page2Alarm(pageParam);
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    private void buildCondition(LambdaQueryWrapper<DeviceRole> lambda, DeviceRoleDTO param) {
        lambda.eq(Objects.nonNull(param.getDeviceId()), DeviceRole::getDeviceId, param.getDeviceId());
        if (StrUtil.isNotEmpty(param.getRoleType())) {
            lambda.eq(DeviceRole::getRoleType, param.getRoleType());
        } else {
            lambda.in(DeviceRole::getRoleType, RoleTypeEnum.getConditions());
        }
        lambda.eq(StrUtil.isNotEmpty(param.getStatus()), DeviceRole::getStatus, param.getStatus());
        lambda.between(Objects.nonNull(param.getStartTime()), DeviceRole::getCreatedAt, param.getStartTime(), param.getEndTime());
        lambda.orderByAsc(DeviceRole::getStatus);
        lambda.orderByDesc(DeviceRole::getUpdatedAt);
    }
}